home *** CD-ROM | disk | FTP | other *** search
- /*
- flipScreen.c
-
- copyright © 1993 by Ken Hornak, Jr.
- 2120 Garden Homes Ct
- Ann Arbor, MI 48103
-
- GEnie: K.Hornak, AppleLink: MEDIMAGE
- (I'm on AOL and CompuServe as well, but I forgot the accounts.)
-
- Permission is granted to use this code in your programs as long
- as the copyright is retained in the code. Please see the documentation
- as to how we actually do the flip.
-
- If you do something really cool with it, I hope you'll share it
- with me. Some day I'd like to add vertical and diagonal axis flips
- as well. It should also be made a small system extension instead of
- a full app, but that can wait until another day.
-
- Typical usage of this code would be:
-
- setupToFlip(&myRec.myGlobals, FALSE);
- flipIt(&myRec.myGlobals, 1, 2);
-
- Delay(30, &ticksNow);
-
- flipIt(&myRec.myGlobals, 1, 1);
- cleanupFlip(&myRec.myGlobals);
-
- killFlip(); // before exiting to remove the sleep task
-
- Note that the code makes provision for segmenting the screen into
- an array of panels and flipping those as well, however I seemed
- to have broken that feature along the way somewhere and am not
- going to fix it for a while.
-
- I sincerely apologize for the strange state of this code, after all
- it was written at MacHack and was truly thrown together with little
- thought as to organization, commenting, parameter passing, naming,
- you name it. This definitely does not reflect my day-to-day programming
- (except for any bugs you may find).
- */
-
-
- #include <stdio.h>
- #include <GestaltEqu.h>
-
-
- #include "flipScreen.h"
-
-
- #define ROTATE_STEPS 20
-
- #define abs(x) ((x) > 0 ? (x) : (-(x)))
- #define RECT_HEIGHT(r) abs((r).bottom-(r).top)
- #define RECT_WIDTH(r) abs((r).right-(r).left)
-
-
- /*
- Globals
- */
-
- Boolean gHasPowerManager = FALSE;
- MySleepInfo myRec;
-
-
- /*
- Prototypes
- */
-
- GWorldPtr getScreen (void);
- void getScreenRect (Rect* theRect);
- void getScreenSection (ScreenPanel* thePanel, Rect* area);
- void rotatePanel (ScreenPanel* thePanel, short h, short v, short how);
- void rotatePanel2 (ScreenPanel* thePanel, short h, short v);
- Boolean lockPanels (FlipInfo* gFlipGlobals);
-
-
- /*
- initFlipper
- */
- void
- initFlipper(void)
- {
- OSErr err = noErr;
- long response;
-
-
- myRec.myGlobals.gNumRows = 1;
- myRec.myGlobals.gNumCols = 1;
- myRec.myGlobals.gNumPanels = myRec.myGlobals.gNumRows *
- myRec.myGlobals.gNumCols;
-
- // Check for the Power Manager.
-
- err = Gestalt(gestaltPowerMgrAttr, &response);
-
- if (err == noErr)
- {
- if ((response >> gestaltPMgrExists) & 0x00000001)
- gHasPowerManager = TRUE;
- }
-
-
- if (gHasPowerManager)
- {
- asm
- {
- move.l a5,myRec.myA5
- }
-
-
- // set up the record before installing onto the sleep queue
- myRec.sleepRec.sleepQLink = 0;
- myRec.sleepRec.sleepQType = slpQType; // sleep queue type, 16
- myRec.sleepRec.sleepQProc = MySleepRtn; // address of some sleep routine
- myRec.sleepRec.sleepQFlags = 0; // reserved field
-
- SleepQInstall(&myRec.sleepRec); // install
- }
-
- } // initFlipper
-
-
-
- /*
- setupToFlip
- */
- void
- setupToFlip(FlipInfo* gFlipGlobals, Boolean grayScreen)
- {
- GrafPtr oldPort;
- short i;
- short rotateSteps;
- CGrafPtr wPort;
- Rect screenRect;
- short curPanel;
- Rect panelRect;
- short j;
- Boolean lockSuccess;
-
- #ifdef DEBUG
- unsigned char str[256];
- #endif
-
-
- GetPort(&oldPort);
-
- GetCWMgrPort(&wPort);
-
- getScreenRect(&screenRect);
-
- rotateSteps = ROTATE_STEPS;
-
- // Create the gworlds containing the screen sections.
-
- curPanel = 0;
- gFlipGlobals->gPanelHeight = RECT_HEIGHT(screenRect) / gFlipGlobals->gNumRows;
- gFlipGlobals->gPanelWidth = RECT_WIDTH(screenRect) / gFlipGlobals->gNumCols;
-
- for (i=0; i<gFlipGlobals->gNumRows; i++)
- {
- panelRect.top = screenRect.top + i * gFlipGlobals->gPanelHeight;
- panelRect.bottom = panelRect.top + gFlipGlobals->gPanelHeight;
-
- for (j=0; j<gFlipGlobals->gNumCols; j++)
- {
- panelRect.left = screenRect.left + j * gFlipGlobals->gPanelWidth;
- panelRect.right = panelRect.left + gFlipGlobals->gPanelWidth;
-
- if (j == gFlipGlobals->gNumCols-1)
- panelRect.right = screenRect.right;
-
- if (i == gFlipGlobals->gNumRows-1)
- panelRect.bottom = screenRect.bottom;
-
- #ifdef DEBUG
- sprintf((char*) str, "ht: %hd, wd: %hd, l: %hd, t: %hd, r: %hd, b: %hd",
- gFlipGlobals->gPanelHeight, gFlipGlobals->gPanelWidth,
- panelRect.left, panelRect.top, panelRect.right, panelRect.bottom);
- CtoPstr((char*) str);
- DebugStr(str);
- #endif
-
- getScreenSection(&gFlipGlobals->gThePanels[curPanel], &panelRect);
-
- curPanel++;
- } // for j
- } // for i
-
- lockSuccess = lockPanels(gFlipGlobals);
-
- if (!lockSuccess)
- DebugStr("\pCouldn't lock the panels.");
-
- SetPort((GrafPtr) wPort);
- ClipRect(&wPort->portRect);
-
- if (grayScreen)
- {
- // Make the whole screen gray.
-
- FillRect(&wPort->portRect, gray);
- }
-
- SetPort(oldPort);
-
- } // setupToFlip
-
-
-
- /*
- flipIt
- */
- void
- flipIt(FlipInfo* gFlipGlobals, short how, short direction)
- {
- GrafPtr oldPort;
- short h;
- short v;
- CGrafPtr wPort;
- short i;
- short j;
- short rotateStep;
- short rotateSteps;
- PixMapHandle pmap;
- long thisRotateTime, rotateTime, numRotates;
-
- #ifdef DEBUG
- Str255 str;
- #endif
-
-
- GetPort(&oldPort);
-
- GetCWMgrPort(&wPort);
-
- rotateSteps = ROTATE_STEPS;
-
- // Make sure the screen gets blanked.
-
- SetPort((GrafPtr) wPort);
-
- ForeColor(blackColor);
- BackColor(whiteColor);
-
- // Setup to rotate each section.
-
- rotateStep = gFlipGlobals->gPanelHeight / rotateSteps;
-
- HideCursor();
-
- numRotates = 0;
-
- if (direction == 1)
- {
- for (h=1; h<=gFlipGlobals->gPanelHeight; h+=rotateStep)
- {
- v = ((gFlipGlobals->gPanelHeight - h) * 3) / 4;
-
- for (i=0; i<gFlipGlobals->gNumPanels; i++)
- {
- rotatePanel(&gFlipGlobals->gThePanels[i], h, v, how);
-
- // Now blit the rotated section to the screen.
-
- SetPort((GrafPtr) wPort);
-
- pmap = gFlipGlobals->gThePanels[i].rotatedPMap;
-
- CopyBits((BitMapPtr) *pmap, (BitMapPtr) *wPort->portPixMap,
- &gFlipGlobals->gThePanels[i].rotatedGWorld->portRect,
- &gFlipGlobals->gThePanels[i].itsGWorld->portRect, srcCopy, NULL);
- } // for i
- } // for h
-
- // Finish by putting the exact image back.
-
- for (i=0; i<gFlipGlobals->gNumPanels; i++)
- {
- // Now blit the correct section to the screen.
-
- SetPort((GrafPtr) wPort);
-
- pmap = GetGWorldPixMap(gFlipGlobals->gThePanels[i].itsGWorld);
-
- if (LockPixels(pmap))
- {
- CopyBits((BitMapPtr) *pmap, (BitMapPtr) *wPort->portPixMap,
- &gFlipGlobals->gThePanels[i].itsGWorld->portRect,
- &gFlipGlobals->gThePanels[i].itsGWorld->portRect, srcCopy, NULL);
-
- UnlockPixels(pmap);
- }
- } // for i
-
- }
- else
- {
- for (h=gFlipGlobals->gPanelHeight-rotateStep; h>0; h-=rotateStep)
- {
- v = ((gFlipGlobals->gPanelHeight - h) * 3) / 4;
-
- for (i=0; i<gFlipGlobals->gNumPanels; i++)
- {
- rotatePanel(&gFlipGlobals->gThePanels[i], h, v, how);
-
- // Now blit the rotated section to the screen.
-
- SetPort((GrafPtr) wPort);
-
- pmap = gFlipGlobals->gThePanels[i].rotatedPMap;
-
- CopyBits((BitMapPtr) *pmap, (BitMapPtr) *wPort->portPixMap,
- &gFlipGlobals->gThePanels[i].rotatedGWorld->portRect,
- &gFlipGlobals->gThePanels[i].itsGWorld->portRect, srcCopy, NULL);
- } // for i
- } // for h
-
- // Make the whole screen gray.
-
- FillRect(&wPort->portRect, gray);
- }
-
- SetPort(oldPort);
-
- ShowCursor();
-
- } // flipIt
-
-
-
- /*
- cleanupFlip
- */
- void
- cleanupFlip(FlipInfo* gFlipGlobals)
- {
- short i;
-
-
- // Dispose of everything.
-
- for (i=0; i<gFlipGlobals->gNumPanels; i++)
- {
- DisposeGWorld(gFlipGlobals->gThePanels[i].itsGWorld);
- gFlipGlobals->gThePanels[i].itsGWorld = NULL;
-
- DisposeGWorld(gFlipGlobals->gThePanels[i].rotatedGWorld);
- gFlipGlobals->gThePanels[i].rotatedGWorld = NULL;
- }
-
- } // cleanupFlip
-
-
-
- /*
- lockPanels
- */
- Boolean
- lockPanels(FlipInfo* gFlipGlobals)
- {
- short i;
-
-
- for (i=0; i<gFlipGlobals->gNumPanels; i++)
- {
- gFlipGlobals->gThePanels[i].itsPMap =
- GetGWorldPixMap(gFlipGlobals->gThePanels[i].itsGWorld);
-
- if (!LockPixels(gFlipGlobals->gThePanels[i].itsPMap))
- return(FALSE);
-
- gFlipGlobals->gThePanels[i].rotatedPMap =
- GetGWorldPixMap(gFlipGlobals->gThePanels[i].rotatedGWorld);
-
- if (!LockPixels(gFlipGlobals->gThePanels[i].rotatedPMap))
- return(FALSE);
- } // for i
-
- return(TRUE);
-
- } // lockPanels
-
-
-
- /*
- rotatePanel
- */
- void
- rotatePanel(ScreenPanel* thePanel, short h, short v, short how)
- {
- PixMapHandle pmap;
- CGrafPtr oldPort;
- GDHandle gdh;
- PixMapHandle rotatedPMap;
- short width;
- short height;
- short row;
- short col;
- Rect theRect;
- short x;
- short y;
- short midY;
- short midX;
- short y1, y2, deltaX;
- Rect srcRect, dstRect;
- Pattern myGray = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
-
- short bytesPerRow;
- short bytesInDstRow;
- Ptr srcPtr;
- Ptr dstPtr;
- short pixelDepth;
- short realBytesPerRow;
-
-
- pmap = thePanel->itsPMap;
-
- // Get the current port settings.
-
- GetGWorld(&oldPort, &gdh);
-
- // Clear the destination gworld.
-
- rotatedPMap = thePanel->rotatedPMap;
-
- SetGWorld(thePanel->rotatedGWorld, thePanel->rotatedGDevice);
-
- theRect = thePanel->itsGWorld->portRect;
-
- ForeColor(blackColor);
- BackColor(whiteColor);
-
- FillRect(&theRect, myGray);
-
-
- bytesPerRow = (**pmap).rowBytes & 0x3FFF;
- srcPtr = GetPixBaseAddr(pmap);
- dstPtr = GetPixBaseAddr(rotatedPMap);
- pixelDepth = (**pmap).pixelSize;
-
- realBytesPerRow = RECT_WIDTH(theRect) * (long) pixelDepth / 8L;
-
- width = RECT_WIDTH(theRect);
- height = RECT_HEIGHT(theRect);
-
- midY = (theRect.top + theRect.bottom) / 2;
-
- y1 = midY - h / 2;
- y2 = y1 + h;
-
- srcRect.left = theRect.left;
- srcRect.right = theRect.right;
-
- dstRect.top = y1;
- dstRect.bottom = y1 + 1;
-
- dstPtr += (long) y1 * (long) bytesPerRow;
-
- for (row = y1; row <= y2; row++)
- {
- y = theRect.top + (long) height * (long) (row - y1) / h;
-
- deltaX = (long) v * (long) (row - y1) / (2 * h);
-
- dstRect.left = theRect.left + deltaX;
- dstRect.right = theRect.right - deltaX;
-
- srcRect.top = y;
- srcRect.bottom = y + 1;
-
- switch (how)
- {
- case 1: // w/block move from both edges
- bytesInDstRow = (long) (dstRect.right - dstRect.left) * (long) pixelDepth / 8L;
-
- // Copy first part of src line
- BlockMove(srcPtr + (long) y * (long) bytesPerRow,
- dstPtr + (long) deltaX * (long) pixelDepth / 8L,
- bytesInDstRow / 2);
-
- // Copy last part of src line
- BlockMove(srcPtr + (long) y * (long) bytesPerRow + (realBytesPerRow - bytesInDstRow / 2),
- dstPtr + (long) deltaX * (long) pixelDepth / 8L + bytesInDstRow / 2,
- bytesInDstRow / 2);
-
- dstPtr += bytesPerRow;
- break;
-
- case 3: // w/block move from left edge
- bytesInDstRow = (long) (dstRect.right - dstRect.left) * (long) pixelDepth / 8L;
-
- if (0) // copy from right
- BlockMove(srcPtr + (long) y * (long) bytesPerRow + (realBytesPerRow - bytesInDstRow),
- dstPtr + (long) deltaX * (long) pixelDepth / 8L,
- bytesInDstRow);
- else // copy from left
- BlockMove(srcPtr + (long) y * (long) bytesPerRow,
- dstPtr + (long) deltaX * (long) pixelDepth / 8L,
- bytesInDstRow);
-
- dstPtr += bytesPerRow;
- break;
-
- case 2: // w/copybits
- CopyBits((BitMapPtr) *pmap, (BitMapPtr) *rotatedPMap,
- &srcRect, &dstRect, srcCopy, NULL);
- break;
-
- default:
- break;
- } // switch
-
-
- dstRect.top++;
- dstRect.bottom++;
- } // for row
-
- SetGWorld(oldPort, gdh);
-
- } // rotatePanel
-
-
-
- /*
- rotatePanel2
- */
- void
- rotatePanel2(ScreenPanel* thePanel, short h, short v)
- {
- PixMapHandle pmap;
- short pixelSize;
- short bytesPerRow;
- short pixelsPerRow;
- short unusedBytes;
- CGrafPtr oldPort;
- GDHandle gdh;
- PixMapHandle rotatedPMap;
- short width;
- short height;
- short row;
- short col;
- Rect theRect;
- short x;
- short y;
- short midY;
- short midX;
- unsigned char* srcValPtr;
- unsigned char* dstValPtr;
- short y1, y2, deltaX;
- Rect srcRect, dstRect;
-
-
- // First we need to know how many bytes might be unused at the
- // end of each row of pixels.
-
- pmap = GetGWorldPixMap(thePanel->itsGWorld);
-
- if (!LockPixels(pmap))
- {
- DebugStr("\pCouldn't lock pixels in rotate2.");
- return;
- }
-
- #if 0
- pixelSize = (**pmap).pixelSize;
- bytesPerRow = (**pmap).rowBytes & 0x3FFF;
- pixelsPerRow = RECT_WIDTH((**pmap).bounds);
- unusedBytes = (long) bytesPerRow - (long) pixelSize * (long) pixelsPerRow / 8L;
- #endif
-
- // Get the current port settings.
-
- GetGWorld(&oldPort, &gdh);
-
- // Clear the destination gworld.
-
- rotatedPMap = GetGWorldPixMap(thePanel->rotatedGWorld);
-
- if (!LockPixels(rotatedPMap))
- {
- DebugStr("\pCouldn't lock rotated pixels in rotate2.");
- return;
- }
-
- SetGWorld(thePanel->rotatedGWorld, thePanel->rotatedGDevice);
-
- theRect = thePanel->itsGWorld->portRect;
-
- BackColor(blackColor);
- EraseRect(&theRect);
-
- ForeColor(blackColor);
- BackColor(whiteColor);
-
- width = RECT_WIDTH(theRect);
- height = RECT_HEIGHT(theRect);
-
- midY = (theRect.top + theRect.bottom) / 2;
-
- y1 = midY - h / 2;
- y2 = y1 + h;
-
- for (row = y1; row <= y2; row++)
- {
- y = theRect.top + (long) height * (long) (row - y1) / h;
-
- deltaX = v * (y2 - row) / (2 * h);
-
- dstRect.left = theRect.left + deltaX;
- dstRect.right = theRect.right - deltaX;
-
- dstRect.top = row;
- dstRect.bottom = row + 1;
-
- srcRect.left = theRect.left;
- srcRect.right = theRect.right;
- srcRect.top = y;
- srcRect.bottom = y + 1;
-
- #if 0
- if (srcRect.top < theRect.top)
- DebugStr("\psrcRect.top is too small.");
- if (srcRect.bottom > theRect.bottom)
- DebugStr("\psrcRect.bottom is too great.");
- #endif
-
- CopyBits((BitMapPtr) *pmap, (BitMapPtr) *rotatedPMap,
- &srcRect, &dstRect, srcCopy, NULL);
- } // for row
-
- UnlockPixels(pmap);
- UnlockPixels(rotatedPMap);
-
- SetGWorld(oldPort, gdh);
-
- } // rotatePanel2
-
-
-
- /*
- getScreenSection
- */
- void
- getScreenSection(ScreenPanel* thePanel, Rect* area)
- {
- GDHandle mainScreen = NULL;
- QDErr err = noErr;
- GWorldPtr theGWorld = NULL;
- short pixelDepth;
- CTabHandle cTable;
- GWorldFlags flags;
- GDHandle aGDevice;
- GDHandle gdh;
- CGrafPtr oldPort;
- CGrafPtr wPort;
- PixMapHandle gworldPMap;
- Rect boundsRect;
- GWorldPtr rotatedGWorld = NULL;
-
- #ifdef DEBUG
- Str255 str;
- #endif
-
-
- mainScreen = GetMainDevice();
-
- aGDevice = mainScreen;
- pixelDepth = (**(**mainScreen).gdPMap).pixelSize;
- flags = noNewDevice | useTempMem;
- cTable = (**(**mainScreen).gdPMap).pmTable;
- boundsRect = *area;
-
- err = NewGWorld(&theGWorld, pixelDepth, &boundsRect, cTable, aGDevice, flags);
-
- if (err != noErr)
- {
- DebugStr("\pCouldn't create the gworld.");
- return;
- }
-
- // Create an identical gworld to hold the rotated image.
-
- err = NewGWorld(&rotatedGWorld, pixelDepth, &boundsRect, cTable, aGDevice, flags);
-
- if (err != noErr)
- {
- DebugStr("\pCouldn't create the rotated gworld.");
- return;
- }
-
- thePanel->rotatedGWorld = rotatedGWorld;
- thePanel->rotatedGDevice = GetGWorldDevice(rotatedGWorld);
-
- // Get the main gworld's gdevice.
-
- aGDevice = GetGWorldDevice(theGWorld);
- thePanel->itsGDevice = aGDevice;
-
- GetGWorld(&oldPort, &gdh);
- SetGWorld(theGWorld, aGDevice);
-
- // Get the screen's port.
-
- GetCWMgrPort(&wPort);
-
- gworldPMap = GetGWorldPixMap(theGWorld);
-
- if (!LockPixels(gworldPMap))
- {
- DebugStr("\pCouldn't lock pixels while grabbing a section.");
- return;
- }
-
- // Copy the contents of the screen into the GWorld.
-
- #ifdef DEBUG
- sprintf((char*) str, "Copying from screen: l: %hd, t: %hd, r: %hd, b: %hd",
- boundsRect.left, boundsRect.top, boundsRect.right, boundsRect.bottom);
- CtoPstr((char*) str);
- DebugStr(str);
- #endif
-
- CopyBits((BitMapPtr) *wPort->portPixMap, (BitMapPtr) *gworldPMap, &boundsRect, &boundsRect,
- srcCopy, NULL);
-
- UnlockPixels(gworldPMap);
-
- SetGWorld(oldPort, gdh);
-
- thePanel->itsGWorld = theGWorld;
-
- } // getScreenSection
-
-
-
- /*
- getScreenRect
- */
- void
- getScreenRect(Rect* theRect)
- {
- GDHandle mainScreen = NULL;
-
-
- mainScreen = GetMainDevice();
-
- *theRect = (**mainScreen).gdRect;
-
- } // getScreenRect
-
-
-
- /*
- getScreen
- */
- GWorldPtr
- getScreen(void)
- {
- GDHandle mainScreen = NULL;
- QDErr err = noErr;
- GWorldPtr theGWorld = NULL;
- short pixelDepth;
- CTabHandle cTable;
- GWorldFlags flags;
- GDHandle aGDevice;
- GDHandle gdh;
- CGrafPtr oldPort;
- CGrafPtr wPort;
- PixMapHandle gworldPMap;
- Rect boundsRect;
-
-
- mainScreen = GetMainDevice();
-
- aGDevice = mainScreen;
- pixelDepth = (**(**mainScreen).gdPMap).pixelSize;
- flags = noNewDevice | useTempMem;
- cTable = (**(**mainScreen).gdPMap).pmTable;
- boundsRect = (**mainScreen).gdRect;
-
- err = NewGWorld(&theGWorld, pixelDepth, &boundsRect, cTable, aGDevice, flags);
-
- if (err != noErr)
- return(NULL);
-
- aGDevice = GetGWorldDevice(theGWorld);
-
- GetGWorld(&oldPort, &gdh);
- SetGWorld(theGWorld, aGDevice);
-
- // Get the screen's port.
-
- GetCWMgrPort(&wPort);
-
- gworldPMap = GetGWorldPixMap(theGWorld);
-
- if (!LockPixels(gworldPMap))
- return(NULL);
-
- // Copy the contents of the screen into the GWorld.
-
- CopyBits((BitMapPtr) *wPort->portPixMap, (BitMapPtr) *gworldPMap, &boundsRect, &boundsRect,
- srcCopy, NULL);
-
- UnlockPixels(gworldPMap);
-
- SetGWorld(oldPort, gdh);
-
- return(theGWorld);
-
- } // getScreen
-
-
-
- /*
- killFlip
- */
- void
- killFlip(void)
- {
-
- SleepQRemove(&myRec.sleepRec);
-
- } // killFlip
-
-
-
- /*
- MySleepRtn
- */
- long
- MySleepRtn(void)
- {
- long reason;
- MySleepInfo* info;
- long theA5;
-
-
- // D0 contains the reason we're being called.
-
- asm
- {
- move.l D0,reason
- move.l A0,info
- }
-
- theA5 = info->myA5;
-
- asm
- {
- move.l theA5,a5
- }
-
-
- switch (reason)
- {
- case 1: // sleep request
- case 2: // sleep demand
- setupToFlip(&info->myGlobals, FALSE);
- flipIt(&info->myGlobals, 1, 2);
- break;
-
- case 3: // wakeup demand
- flipIt(&info->myGlobals, 1, 1);
- cleanupFlip(&info->myGlobals);
- break;
-
- default:
- break;
- } // switch
-
- return(0); // always succeed
-
- } // MySleepRtn
-
-
-
-
-
-
-
-
-
-